#include "CompilerContext.h"

#include "ScriptCompiler/ScriptFileContext.h"
#include "ScriptCompiler/Token/FilePosition.h"
#include "ScriptCompiler/Token/Token.h"

CString CCompilerContext::CreatePositionInfo(std::shared_ptr<CScriptFileContext> File, const SScriptFilePosition &PositionInFile)
{
    CString FilePathLine=U"In  File : " + File->FilePath.ToString() + U" ";

    CString LineColumn=U"Line [" + CString(PositionInFile.LineIndex+1) + U"] Column [" + CString(PositionInFile.ColumnIndex+1) + U"]\n";

    CString SourceCodeLine;
    {
        uint64_t LineEnd= 
            PositionInFile.LineIndex==File->LineStartIndexList.Num()-1 
            ? File->FileContent.Num()-2 
            : File->LineStartIndexList[PositionInFile.LineIndex+1];
        TVector<char32_t> _LineContent=File->FileContent.Slice(File->LineStartIndexList[PositionInFile.LineIndex],LineEnd);
        _LineContent.Add(U'\0');
        SourceCodeLine=CString(_LineContent.Data());
    }

    // creatre position mark ^
    CString PositionMarkLine;
    {
        PositionMarkLine.Reserve(PositionInFile.ColumnIndex+1);
        for(uint64_t i=0;i<PositionInFile.ColumnIndex;i++)
        {
            PositionMarkLine+=U' ';
        }
        for(uint64_t i=0;i<PositionInFile.CharactorNum;i++)
        {
            PositionMarkLine+=U'^';
        }
    }

    return  FilePathLine +LineColumn+  SourceCodeLine + U"\n" + PositionMarkLine + U"\n";
}

void CCompilerContext::RaiseError(const SErrorMessage &ErrorMessage)
{
    if(ErrorMessage.bIsWarning)
    {
        ErrorInfo.WarningCount++;
        auto MessageString=U"[Warning:"+CString::CreateBase10(ErrorMessage.ErrorCode,5)+ U"]" + CreatePositionInfo(ScriptFiles[ErrorMessage.File],SScriptFilePosition(ErrorMessage.LineIndex,ErrorMessage.ColumnIndex,ErrorMessage.CharNum)) + U"\n" + ErrorMessage.ErrorMessage;
        ErrorInfo.Messages.Add(MessageString);
    }
    else
    {
        ErrorInfo.ErrorCount++;
        auto MessageString=U"[Error:"+CString::CreateBase10(ErrorMessage.ErrorCode,5)+ U"]" + CreatePositionInfo(ScriptFiles[ErrorMessage.File],SScriptFilePosition(ErrorMessage.LineIndex,ErrorMessage.ColumnIndex,ErrorMessage.CharNum)) + U"\n" + ErrorMessage.ErrorMessage;
        ErrorInfo.Messages.Add(MessageString);
    }
}

void CCompilerContext::RaiseError(uint64_t ErrorCode,const SPath &File, const SScriptFilePosition &PositionInFile, const CString &InErrorMessage,bool bIsWarning)
{
    SErrorMessage ErrorMessage;
    ErrorMessage.File=File;
    ErrorMessage.LineIndex=PositionInFile.LineIndex;
    ErrorMessage.ColumnIndex=PositionInFile.ColumnIndex;
    ErrorMessage.CharNum=PositionInFile.CharactorNum;
    ErrorMessage.ErrorMessage=InErrorMessage;
    ErrorMessage.bIsWarning=bIsWarning;
    ErrorMessage.ErrorCode=ErrorCode;
    RaiseError(ErrorMessage);
}

void CCompilerContext::RaiseError(uint64_t ErrorCode,const SPath &File, std::shared_ptr<CScriptToken> InToken, const CString &InErrorMessage,bool bIsWarning)
{
    RaiseError(ErrorCode,File,InToken->FilePosition,InErrorMessage,bIsWarning);
}

void CCompilerContext::RaiseError(uint64_t ErrorCode,const SPath &File, const CString &InErrorMessage,bool bIsWarning)
{
    if(bIsWarning)
    {
        ErrorInfo.WarningCount++;
        ErrorInfo.Messages.Add(U"[Warning:"+CString::CreateBase10(ErrorCode)+U"] In File" + File.ToString() + U'\n' + InErrorMessage);
    }
    else
    {
        ErrorInfo.ErrorCount++;
        ErrorInfo.Messages.Add(U"[Error:"+CString::CreateBase10(ErrorCode)+U"] In File" + File.ToString() + U'\n' + InErrorMessage);
    }
}
